package com.quick.proxy.client;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.quick.proxy.client.config.ClientConfig;
import com.quick.proxy.core.*;
import com.quick.proxy.core.pojo.ProxyMapping;
import com.quick.proxy.core.utils.ByteUtils;
import com.quick.proxy.core.utils.ProtocolUtils;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Description: 代理消息身份验证处理程序
 * Author: 吃素不吃肉
 * Date: 2023/7/9
 *
 * @author 吃素不吃肉
 */
@Match(CmdTypeConstants.AUTH)
@Component
@Slf4j
public class ProxyMessageAuthHandler implements ProxyMessageHandler {
    @Autowired
    private ClientConfig clientConfig;

    /**
     * 接收的数据帧包
     *
     * @param ctx          上下文
     * @param proxyMessage 帧报文
     */
    @Override
    public void cmdResponse(ChannelHandlerContext ctx, ProxyMessage proxyMessage) {
        log.info("认证结果:{}", ByteUtils.hexToString(proxyMessage.getData()));
    }

    public void authRequest(ChannelHandlerContext ctx) {
        //开始认证
        if (!checkProxyMappings(clientConfig.getProxyMappings())) {
            ctx.channel().close();
            System.exit(-1);
            return;
        }
        Map<String, Object> data = new HashMap<>(1);
        data.put(clientConfig.getAccessKey(), clientConfig.getProxyMappings());
        String accessKeyData = JSONUtil.toJsonStr(data);
        log.info("认证开始:{}", accessKeyData);
        byte[] bytes = ProtocolUtils.getByte(CmdTypeConstants.AUTH, accessKeyData.getBytes(StandardCharsets.UTF_8), true);
        ctx.channel().attr(ChannelAttribute.ACCESS_KEY_PROXY_CHANNEL).set(clientConfig.getAccessKey());
        ctx.channel().writeAndFlush(bytes);
    }

    /**
     * 校验映射参数
     *
     * @param proxyMappings 映射参数
     * @return true 校验通过，false 校验失败:停止程序
     */
    private boolean checkProxyMappings(List<ProxyMapping> proxyMappings) {
        String regex = "^(?:\\d{1,3}\\.){3}\\d{1,3}:\\d{1,5}$";
        if (!CollectionUtils.isEmpty(proxyMappings)) {
            for (int i = 0; i < proxyMappings.size(); i++) {
                Integer mappingPort = proxyMappings.get(i).getMappingPort();
                String realProxyClientAddress = proxyMappings.get(i).getRealProxyClientAddress();
                if (StrUtil.isNotEmpty(realProxyClientAddress) && !realProxyClientAddress.matches(regex)) {
                    log.warn(StrUtil.format("Error in the realProxyClientAddress parameter {} for elements with index {} in the collection proxyMappings", realProxyClientAddress, i));
                    return false;
                }
                if (mappingPort != null && (mappingPort > 65535 || mappingPort <= 0)) {
                    log.warn(StrUtil.format("Error in the mappingPort parameter {} for elements with index {} in the collection proxyMappings", mappingPort, i));
                    return false;
                }
            }
        }
        return true;
    }
}
